%option noyywrap
%{
    #define YY_NO_UNPUT
    #define YY_NO_INPUT

    #include "parser.h"
    #include <ostream>
    #include <fstream>
    #include <string>
    using namespace std;

    extern FILE *yyin; 
    extern FILE *yyout;
    extern bool dump_tokens;

    void DEBUG_FOR_LAB4(std::string s){
        std::string DEBUG_INFO = "[DEBUG LAB4]: \t" + s + "\n";
        fputs(DEBUG_INFO.c_str(), yyout);
    }
%}

DECIMIAL ([1-9][0-9]*|0)
HEXA (0x|0X)[0-9a-fA-F]*
OCTAL (0)[0-7]*
ID [[:alpha:]_][[:alpha:][:digit:]_]*
EOL (\r\n|\n|\r)
WHITE [\t ]
TYPE ((int)|(void))
COMMENT [/][*][[:alpha:][:digit:]_ \n\t;,.=+-><\)\(\{\}\[\]]*[*][/]
COMM [/][/][[:alpha:][:digit:]_ \t;,.=+-><\)\(\{\}\[\]]*
IDLIST (({WHITE}*{ID}{WHITE}*,)|({WHITE}*{ID}{WHITE}*={WHITE}*({DECIMIAL}|{OCTAL}|{HEXA}){WHITE}*,)|({WHITE}*({DECIMIAL}|{OCTAL}|{HEXA}){WHITE}*,))+{WHITE}*({ID}|({ID}{WHITE}*={WHITE}*({DECIMIAL}|{OCTAL}|{HEXA}))|({DECIMIAL}|{OCTAL}|{HEXA}))
FUNCPARALIST ({WHITE}*{TYPE}{WHITE}*{ID}{WHITE}*,)+{WHITE}*({TYPE}{WHITE}*{ID})
%x BLOCKCOMMENT

%%

"int" {
    /*
    * Questions: 
    *   Q1: Why we need to return INT in further labs?
    *   Q2: What is "INT" actually?
    */
    if(dump_tokens)
        DEBUG_FOR_LAB4("INT\tint");
    return INT;
}
"void" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("VOID\tvoid");
    return VOID;
}
"if" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("IF\tif");
    return IF;
};
"while" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("WHILE\twhile");
    return WHILE;
};
"else" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("ELSE\telse");
    return ELSE;
};
"return" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("RETURN\treturn");
    return RETURN;
}

"=" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("ASSIGN\t=");
    return ASSIGN;
}
"<" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("LESS\t<");
    return LESS;
}
"+" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("ADD\t+");
    return ADD;
}
"-" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("SUB\t-");
    return SUB;
}
"&&" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("AND\t&&");
    return AND;
}
">" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("MORE\t>");
    return MORE;
}
">=" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("ME\t>=");
    return ME;
}
"<=" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("LE\t<=");
    return LE;
}
"==" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("EQ\t==");
    return EQ;
}
"!=" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("UE\t!=");
    return UE;
}
"||" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("OR\t||");
    return OR;
}
"*" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("MUL\t*");
    return MUL;
}
"%" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("MOD\t%");
    return MOD;
}
"/" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("DIV\t/");
    return DIV;
}
";" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("SEMICOLON\t;");
    return SEMICOLON;
}
"(" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("LPAREN\t(");
    return LPAREN;
}
")" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("RPAREN\t)");
    return RPAREN;
}
"{" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("LBRACE\t{");
    return LBRACE;
}
"}" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("RBRACE\t}");
    return RBRACE;
}
"," {
    if(dump_tokens)
        DEBUG_FOR_LAB4("COMMA\t,");
    return COMMA;
}
"const" {
    if(dump_tokens)
        DEBUG_FOR_LAB4("CONST\tconst");
    return CONST;
}
{DECIMIAL} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    yylval.itype = atoi(yytext);
    return INTEGER;
}
{HEXA} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    int len=strlen(yytext);
    int re=0;
    for(int i=2;i<len;i++){
            re*=16;
            if(yytext[i]>='0'&&yytext[i]<='9')re+=yytext[i]-'0';
            if(yytext[i]>='A'&&yytext[i]<='Z')re+=yytext[i]-'A'+10;
            else re+=yytext[i]-'a'+10;
        }
    yylval.itype = re;
    return INTEGER;
}
{OCTAL} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    int len=strlen(yytext);
    int re=0;
    for(int i=1;i<len;i++){
            re*=8;
            re+=yytext[i]-'0';
        }
    yylval.itype = re;
    return INTEGER;
}
{COMM} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    char *lexeme;
    lexeme = new char[strlen(yytext) + 1];
    for(long unsigned int i=2;i<strlen(yytext);i++){
        lexeme[i-2]=yytext[i];
    }
    yylval.strtype = lexeme;
    return COM;
}
{COMMENT} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    char *lexeme;
    lexeme = new char[strlen(yytext) + 1];
    for(long unsigned int i=2;i<strlen(yytext)-2;i++){
        lexeme[i-2]=yytext[i];
    }
    yylval.strtype = lexeme;
    return COM;
}
{ID} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    char *lexeme;
    lexeme = new char[strlen(yytext) + 1];
    strcpy(lexeme, yytext);
    yylval.strtype = lexeme;
    return ID;
}
{FUNCPARALIST} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    char *lexeme;
    lexeme = new char[strlen(yytext) + 1];
    strcpy(lexeme, yytext);
    yylval.strtype = lexeme;
    return FUNCPARALIST;
}
{IDLIST} {
    if(dump_tokens)
        DEBUG_FOR_LAB4(yytext);
    char *lexeme;
    lexeme = new char[strlen(yytext) + 1];
    strcpy(lexeme, yytext);
    yylval.strtype = lexeme;
    return IDLIST;
}

{EOL} yylineno++;
{WHITE}
%%
